import express from 'express';
import { prisma } from '../app';
import { asyncHandler, createError } from '../middleware/errorHandler';
import { authenticateToken, AuthRequest } from '../middleware/auth';
import { validateAlgorithmInput } from '../middleware/validation';

const router = express.Router();

// Get all algorithm problems for the authenticated user
router.get('/', authenticateToken, asyncHandler(async (req: AuthRequest, res) => {
  const userId = req.user!.id;
  const { page = 1, limit = 10, difficulty, search } = req.query;

  const pageNum = parseInt(page as string);
  const limitNum = parseInt(limit as string);
  const offset = (pageNum - 1) * limitNum;

  const where: any = { userId };
  
  if (difficulty && ['easy', 'medium', 'hard'].includes(difficulty as string)) {
    where.difficulty = difficulty;
  }
  
  if (search) {
    where.OR = [
      { title: { contains: search as string } },
      { description: { contains: search as string } }
    ];
  }

  const [problems, total] = await Promise.all([
    prisma.algorithmProblem.findMany({
      where,
      include: {
        solution: {
          select: {
            id: true,
            savedAt: true
          }
        }
      },
      orderBy: { createdAt: 'desc' },
      skip: offset,
      take: limitNum
    }),
    prisma.algorithmProblem.count({ where })
  ]);

  res.json({
    success: true,
    data: {
      problems,
      pagination: {
        page: pageNum,
        limit: limitNum,
        total,
        totalPages: Math.ceil(total / limitNum)
      }
    }
  });
}));

// Get a specific algorithm problem by ID
router.get('/:id', authenticateToken, asyncHandler(async (req: AuthRequest, res) => {
  const problemId = parseInt(req.params.id);
  const userId = req.user!.id;

  if (isNaN(problemId)) {
    throw createError('Invalid problem ID', 400);
  }

  const problem = await prisma.algorithmProblem.findFirst({
    where: {
      id: problemId,
      userId
    },
    include: {
      solution: true
    }
  });

  if (!problem) {
    throw createError('Algorithm problem not found', 404);
  }

  res.json({
    success: true,
    data: { problem }
  });
}));

// Create a new algorithm problem
router.post('/', authenticateToken, validateAlgorithmInput, asyncHandler(async (req: AuthRequest, res) => {
  const { title, description, difficulty } = req.body;
  const userId = req.user!.id;

  const problem = await prisma.algorithmProblem.create({
    data: {
      title,
      description,
      difficulty,
      userId
    },
    include: {
      solution: true
    }
  });

  // Record activity
  const today = new Date();
  today.setHours(0, 0, 0, 0);

  await prisma.userActivity.upsert({
    where: {
      userId_date: {
        userId,
        date: today
      }
    },
    update: {
      count: {
        increment: 1
      }
    },
    create: {
      userId,
      date: today,
      count: 1
    }
  });

  res.status(201).json({
    success: true,
    message: 'Algorithm problem created successfully',
    data: { problem }
  });
}));

// Update an algorithm problem
router.put('/:id', authenticateToken, validateAlgorithmInput, asyncHandler(async (req: AuthRequest, res) => {
  const problemId = parseInt(req.params.id);
  const userId = req.user!.id;
  const { title, description, difficulty } = req.body;

  if (isNaN(problemId)) {
    throw createError('Invalid problem ID', 400);
  }

  // Check if problem exists and belongs to user
  const existingProblem = await prisma.algorithmProblem.findFirst({
    where: {
      id: problemId,
      userId
    }
  });

  if (!existingProblem) {
    throw createError('Algorithm problem not found', 404);
  }

  const problem = await prisma.algorithmProblem.update({
    where: { id: problemId },
    data: {
      title,
      description,
      difficulty
    },
    include: {
      solution: true
    }
  });

  res.json({
    success: true,
    message: 'Algorithm problem updated successfully',
    data: { problem }
  });
}));

// Delete an algorithm problem
router.delete('/:id', authenticateToken, asyncHandler(async (req: AuthRequest, res) => {
  const problemId = parseInt(req.params.id);
  const userId = req.user!.id;

  if (isNaN(problemId)) {
    throw createError('Invalid problem ID', 400);
  }

  // Check if problem exists and belongs to user
  const existingProblem = await prisma.algorithmProblem.findFirst({
    where: {
      id: problemId,
      userId
    }
  });

  if (!existingProblem) {
    throw createError('Algorithm problem not found', 404);
  }

  // Delete the problem (solution will be deleted due to cascade)
  await prisma.algorithmProblem.delete({
    where: { id: problemId }
  });

  res.json({
    success: true,
    message: 'Algorithm problem deleted successfully'
  });
}));

// Save or update code solution for a problem
router.put('/:id/code', authenticateToken, asyncHandler(async (req: AuthRequest, res) => {
  const problemId = parseInt(req.params.id);
  const userId = req.user!.id;
  const { code } = req.body;

  if (isNaN(problemId)) {
    throw createError('Invalid problem ID', 400);
  }

  if (typeof code !== 'string') {
    throw createError('Code must be a string', 400);
  }

  // Check if problem exists and belongs to user
  const existingProblem = await prisma.algorithmProblem.findFirst({
    where: {
      id: problemId,
      userId
    }
  });

  if (!existingProblem) {
    throw createError('Algorithm problem not found', 404);
  }

  // Upsert the solution
  const solution = await prisma.algorithmSolution.upsert({
    where: { problemId },
    update: {
      code,
      savedAt: new Date()
    },
    create: {
      problemId,
      code
    }
  });

  res.json({
    success: true,
    message: 'Code saved successfully',
    data: { solution }
  });
}));

// Get code solution for a problem
router.get('/:id/code', authenticateToken, asyncHandler(async (req: AuthRequest, res) => {
  const problemId = parseInt(req.params.id);
  const userId = req.user!.id;

  if (isNaN(problemId)) {
    throw createError('Invalid problem ID', 400);
  }

  // Check if problem exists and belongs to user
  const existingProblem = await prisma.algorithmProblem.findFirst({
    where: {
      id: problemId,
      userId
    }
  });

  if (!existingProblem) {
    throw createError('Algorithm problem not found', 404);
  }

  const solution = await prisma.algorithmSolution.findUnique({
    where: { problemId }
  });

  res.json({
    success: true,
    data: { solution }
  });
}));

export default router;